﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BepInEx;
using CheatMenu.Menus;
using UnityEngine;

namespace CheatMenu.Managers
{
    public enum BindType
    {
        Action,
        Menu,
    }

    public class DefaultBind
    {
        public string Name;
        public KeyCode KeyCode;
        public bool CanUnbind = true;

        public DefaultBind(string name, KeyCode keyCode)
        {
            Name = name;
            KeyCode = keyCode;
        }

        public DefaultBind(string name, KeyCode keyCode, bool canUnbind) : this(name, keyCode)
        {
            CanUnbind = canUnbind;
        }
    }

    public class Keybind
    {
        public string Name;
        public BindType BindType = BindType.Action;
        public Action Action;
        public ConfigWrapper<KeyCode> ConfigKeyCode;
        public bool CanUnbind = true;

        public KeyCode KeyCode
        {
            get => ConfigKeyCode.Value;
            set => ConfigKeyCode.Value = value;
        }

        public Keybind(ConfigWrapper<KeyCode> config, Action action, BindType bindType = BindType.Action, bool canUnbind = true)
        {
            Name = config.Key;
            ConfigKeyCode = config;
            BindType = bindType;
            CanUnbind = canUnbind;
            Action = action;
        }

        public Keybind(ConfigWrapper<KeyCode> config, bool canUnbind = true) 
            : this(config, () => { if (MenuManager.TryGetMenu(config.Key, out MenuBase menu)) menu.ToggleShown(); }, BindType.Menu, canUnbind)
        {
        }
    }

    public static class BindManager
    {
        private static readonly DefaultBind[] menuBinds = 
        {
            new DefaultBind("CheatMenu", KeyCode.F9, false),
            new DefaultBind("StateViewer", KeyCode.F10),
            new DefaultBind("Commands", KeyCode.F11),
            new DefaultBind("Screenshot", KeyCode.None),
            new DefaultBind("Config", KeyCode.None),
            new DefaultBind("Debug", KeyCode.None),
            new DefaultBind("LoadScene", KeyCode.None)
        };

        public static List<Keybind> Keybinds { get; private set; } = new List<Keybind>();
        public static bool IgnoreNext { get; set; } = false;

        public static void Initialize(CheatMenuPlugin plugin)
        {
            for (int i = 0; i < menuBinds.Length; i++)
            {
                Keybinds.Add(new Keybind(new ConfigWrapper<KeyCode>(menuBinds[i].Name, plugin, menuBinds[i].KeyCode), menuBinds[i].CanUnbind));
            }
            Keybinds.Add(new Keybind(new ConfigWrapper<KeyCode>("Time-1", plugin, KeyCode.None), () => StateManager.AddInt("time", -1)));
            Keybinds.Add(new Keybind(new ConfigWrapper<KeyCode>("Time+1", plugin, KeyCode.None), () => StateManager.AddInt("time", 1)));
        }

        public static void OnUpdate()
        {
            for (int i = 0; i < Keybinds.Count; i++)
            {
                Keybind bind = Keybinds[i];
                if (bind.KeyCode != KeyCode.None && Input.GetKeyDown(bind.KeyCode))
                {
                    if (IgnoreNext)
                        IgnoreNext = false;
                    else
                        bind.Action?.Invoke();
                }
            }
        }

        public static Keybind GetKeyBind(string name)
        {
            Keybind result = null;

            for (int i = 0; i < Keybinds.Count; i++)
            {
                if (Keybinds[i].Name == name)
                {
                    result = Keybinds[i];
                    break;
                }
            }

            return result;
        }

        public static KeyCode GetBoundKeyForMenu(MenuBase menu) => GetKeyBind(menu.Name)?.KeyCode ?? KeyCode.None;
    }
}
